﻿

namespace Common.Algorithm.Core;

internal class MortonCodeService<T>
{
    /// <summary>
    /// // 二进制长度    默认 32 -- 4,294,967,296*4,294,967,296 像素
    /// 
    /// </summary>
    public static int binaryLen { get; set; } = 32;

    //public static HashSet<Tuple<string, long, T>> mortonCodeSet = new HashSet<Tuple<string, long, T>>();

    /// <summary>
    /// 2D  用于平面四叉树
    /// </summary>
    /// <param name="_matrix"></param> 
    public static SortedSet<Tuple<string, long, T>> FromMatrix2D(T[,] _matrix)
    {
        var matrix2d = _matrix;
        int rowNum = matrix2d.GetLength(0);
        var colNum = matrix2d.GetLength(1);

        SortedSet<Tuple<string, long, T>> set = new SortedSet<Tuple<string, long, T>>();
        ////Dictionary<string, double> binaryDict = new Dictionary<string, double>();
        for (int i = 0; i < rowNum; i++)
        {
            for (int j = 0; j < colNum; j++)
            {
                T value = matrix2d[i, j];
                // 转换为16位 二进制字符串
                string rowBinStr = Convert.ToString(i, 2).PadLeft(binaryLen / 2, '0');
                // 转换为16位 二进制字符串
                string colBinStr = Convert.ToString(j, 2).PadLeft(binaryLen / 2, '0');

                var mortonCode = string.Empty;
                for (int k = 0; k < Math.Max(rowBinStr.Length, colBinStr.Length); k++)
                {
                    mortonCode += rowBinStr.Length <= k ? '0' : rowBinStr[k];
                    mortonCode += colBinStr.Length <= k ? '0' : colBinStr[k];
                }
                //二维 16+16=32位 补到64位
                mortonCode = mortonCode.PadLeft(binaryLen * 2, '0');
                long decimalNumber = Convert.ToInt64(mortonCode, 2); // 转换为十进制整数

                set.Add(Tuple.Create(mortonCode, decimalNumber, value));
            }
        }
        //mortonCodeSet = hashSet;
        return set;
    }


    /// <summary>
    /// 3D  用于空间八叉树
    /// </summary>
    /// <param name="_matrix"></param>
    public static SortedSet<Tuple<string, long, T>> FromMatrix3D(T[,,] _matrix)
    {
        var matrix3d = _matrix;
        int rowNum = matrix3d.GetLength(0);
        int colNum = matrix3d.GetLength(1);
        int depNum = matrix3d.GetLength(2);

        var set = new SortedSet<Tuple<string, long, T>>();
        ////Dictionary<string, double> binaryDict = new Dictionary<string, double>();
        for (int i = 0; i < rowNum; i++)
        {
            for (int j = 0; j < colNum; j++)
            {
                for (int k = 0; k < depNum; k++)
                {
                    T value = matrix3d[i, j, k];

                    // 转换为16位 二进制字符串
                    string rowBinStr = Convert.ToString(i, 2).PadLeft(binaryLen / 2, '0');
                    // 转换为16位 二进制字符串
                    string colBinStr = Convert.ToString(j, 2).PadLeft(binaryLen / 2, '0');
                    // 转换为16位 二进制字符串
                    string depBinStr = Convert.ToString(k, 2).PadLeft(binaryLen / 2, '0');

                    int maxCount = (new int[] { rowBinStr.Length, colBinStr.Length, depBinStr.Length }).Max();
                    var mortonCode = string.Empty;
                    for (int b = 0; b < maxCount; b++)
                    {
                        mortonCode += rowBinStr.Length <= b ? '0' : rowBinStr[b];
                        mortonCode += colBinStr.Length <= b ? '0' : colBinStr[b];
                        mortonCode += depBinStr.Length <= b ? '0' : depBinStr[b];
                    }
                    //三维16+16+16=48位 补到64位
                    mortonCode = mortonCode.PadLeft(binaryLen * 2, '0');
                    long decimalNumber = Convert.ToInt64(mortonCode, 2); // 转换为十进制整数
                    set.Add(Tuple.Create(mortonCode, decimalNumber, value));
                }

            }
        }
        return set;
    }

    public static Stack<Tuple<string, long, T>> GenTree(SortedSet<Tuple<string, long, T>> _mortonCode,
        Func<T[], bool> targetFunc, int dimension = 2)
    {
        var mortonCode = _mortonCode;
        int unitLen = (int)Math.Pow(2, dimension);//2*2=4 , 2*2*2=8

        Stack<Tuple<string, long, T>> stack = new Stack<Tuple<string, long, T>>();

        for (int i = 0; i < mortonCode.LongCount() / unitLen; i += unitLen)
        {
            var tmpList = new Tuple<string, long, T>[unitLen];
            for (int j = 0; j < unitLen; j++)
            {
                var tuple = mortonCode.ElementAt(i + j);
                tmpList[j] = tuple;
            }

            bool isSame = targetFunc(tmpList.Select(t => t.Item3).ToArray());
            //判断四个连续的单元是否相等
            if (isSame)
            {
                //相等，最小入栈
                stack.Push(tmpList.OrderBy(t => t.Item2).First());
            }
            else
            {   //不相等，则按MD码大小入栈
                tmpList.OrderBy(t => t.Item2).ToList().ForEach(t => stack.Push(t));
            }
            //判断栈顶四个元素是否相等
            var topV = stack.Peek().Item3;
            bool topIsSame = targetFunc(stack.Take(unitLen).Select(t => t.Item3).ToArray());   //   .All(t=>  ) ;
            if (topIsSame)
            {
                for (int top = 0; top < 3; top++)
                {
                    stack.Pop();
                }
            }
        }

        return stack;
    }

}
